<?php

class Emms_Class_Loan_PmtPlan
{
    protected $_interestCalculation;
    protected $_calendarType;
    protected $_installments;
    protected $_paymentFrequency;
    protected $_deliveryDate;
    protected $_firstPaymentDate;
    protected $_annualPercentageRate;
    protected $_loanInsurancePct;
    protected $_healthInsurancePct;
    protected $_administrativeFeePct;
    protected $_principalGraceRate;
    protected $_principal;
    protected $_principalGraceEndDate;
    protected $_principalGraceMargin;
    protected $_principalGrace;
    protected $_delayGrace;
    protected $_delayPenaltyRate;
    protected $_delayPenaltyFixedCharge;
    protected $_term;
    protected $_pmt;
    protected $_gracePmt;
    protected $_metadata;
    protected $_plan;
    protected $_loan;
    
    public function __construct() {
        $args = func_get_args(); 
        if(isset($args[0])&&is_array($args[0])) {
            $this->_constructFromArray($args[0]);
        } elseif(isset($args[0])&&is_numeric($args[0])) {
            $loans = new Loans();
            try {
                $this->_loan = $loans->getRecord($args[0]); 
                $this->_constructFromArray($this->_loan->d->toArray());
            } catch (Exception $e) {
                throw new Exception($e->getMessage()); 
            }
        } else {
            throw new Exception($this->translate("Invalid loan code or parameters, the payment plan couldn't be created.")); 
        }
    }
    
    protected function _constructFromArray($values)
    {
        $this->_setInterestCalculation($values['InterestCalculation'])
             ->_setCalendarType($values['CalendarType'])
             ->_setInstallments($values['Installments'])
             ->_setPaymentFrequency($values['PaymentFrequency'])
             ->_setDeliveryDate(isset($values['InterestFromDate']) ? $values['InterestFromDate'] :
                 isset($values['DeliveryDate']) ? $values['DeliveryDate'] : $values['TentativeDeliveryDate'])
             ->_setFirstPaymentDate(
                     isset($values['NextPaymentDate']) ? $values['NextPaymentDate'] : 
                         isset($values['ExpectedFirstPaymentDate']) ? $values['ExpectedFirstPaymentDate'] : 
                             isset($values['TentativeFirstPaymentDate']) ? $values['TentativeFirstPaymentDate'] : 
                                 $values['FirstPaymentDate'])
             ->_setAnnualPercentageRate($values['AnnualPercentageRate'])
             ->_setLoanInsurancePct($values['LoanInsurancePct'])
             ->_setHealthInsurancePct($values['HealthInsurancePct'])
             ->_setAdministrativeFeePct($values['AdministrativeFeePct'])
             ->_setPrincipalGraceRate($values['PrincipalGraceRate'])
             ->_setPrincipal($values['Principal'])
             ->_setPrincipalGraceEndDate()
             ->_setPrincipalGraceMargin($values['PrincipalGraceMargin'])
             ->_setPrincipalGrace()
             ->_setDelayGrace($values['DelayGrace'])
             ->_setDelayPenaltyRate($values['DelayPenaltyRate'])
             ->_setDelayPenaltyFixedCharge($values['DelayPenaltyFixedCharge'])
             ->_setTerm()
             ->_setPmt()
             ->_setGracePmt()
             ->_setMetadata()
             ->_setPlan();
    }
    
    protected function _setPlan()
    {
        $this->_plan = new plan();
        
        $this->_plan->pmt = $this->_pmt;
        
        $this->_plan->kp = $this->_principal;
        $this->_plan->kh = 0.01 * $this->_principal * $this->_healthInsurancePct;
        $this->_plan->kl = 0.01 * $this->_principal * $this->_loanInsurancePct;
        $this->_plan->ka = 0.01 * $this->_principal * $this->_administrativeFeePct;
        
        $this->_plan->kpP = 100 / (100 + $this->_healthInsurancePct + $this->_loanInsurancePct + $this->_administrativeFeePct);
        $this->_plan->khP = $this->_healthInsurancePct / (100 + $this->_healthInsurancePct + $this->_loanInsurancePct + $this->_administrativeFeePct);
        $this->_plan->klP = $this->_loanInsurancePct / (100 + $this->_healthInsurancePct + $this->_loanInsurancePct + $this->_administrativeFeePct);
        $this->_plan->kaP = $this->_administrativeFeePct / (100 + $this->_healthInsurancePct + $this->_loanInsurancePct + $this->_administrativeFeePct);
        
        $this->_plan->balanceKp = $this->_loan ? $this->_loan->d->BalancePrincipal         : $this->_plan->kp;
        $this->_plan->balanceKh = $this->_loan ? $this->_loan->d->BalanceHealthInsurance   : $this->_plan->kh;
        $this->_plan->balanceKl = $this->_loan ? $this->_loan->d->BalanceLoanInsurance     : $this->_plan->kl;
        $this->_plan->balanceKa = $this->_loan ? $this->_loan->d->BalanceAdministrativeFee : $this->_plan->ka;
        
        //$this->_plan->annualEffectiveRate;
                
        $this->_plan->xpPmtDate = $this->_loan ? $this->_loan->d->NextPaymentDate     : $this->_firstPaymentDate;
        $this->_plan->xpPmt     = $this->_loan ? $this->_loan->d->PaymentMnt          : $this->_plan->pmt;
        $this->_plan->rFromDate = $this->_loan ? $this->_loan->d->PreviousPaymentDate : $this->_principalGraceEndDate;
        
        $this->_plan->schedule = $this->_getSchedule();
    }
    
    protected function _getSchedule()
    {
        $pmt = array();
        $totals = array(
            'inx' => $this->translate("TOTALs"), 
            'Date' => ' ', 
            'HealthInsurance' => 0, 
            'LoanInsurance' => 0, 
            'AdministrativeFee' => 0, 
            'Principal' => 0, 
            'Interest' => 0, 
            'Pmt' => ' ', 
            'Penalties' => 0,
            'Delay' => 0,
            'BalancePrincipal' => ' ',
            'ReceiptId' => ' ',
            'TransactionId' => ' ',
            'Username' => ' '); 
                 
        $c = 0;         
        if($this->_loan) {
            foreach($this->_loan->r->payments->toArray() as $p) {    
                $pmt[$c]['inx']               = $c + 1;
                $pmt[$c]['Date']              = $p['Date'];
                $pmt[$c]['HealthInsurance']   = $p['HealthInsurance'];
                $pmt[$c]['LoanInsurance']     = $p['LoanInsurance'];
                $pmt[$c]['AdministrativeFee'] = $p['AdministrativeFee'];
                $pmt[$c]['Principal']         = $p['Principal'];
                $pmt[$c]['Interest']          = $p['Interest']; //
                $pmt[$c]['Pmt']               = $p['Pmt'];
                $pmt[$c]['Penalties']         = $p['Penalties'];
                $pmt[$c]['Delay']             = $p['Delay'];
                $pmt[$c]['BalancePrincipal']  = $p['BalancePrincipal'];
                $pmt[$c]['ReceiptId']         = $p['ReceiptId'];
                $pmt[$c]['TransactionId']     = $p['TransactionId'];
                $pmt[$c]['Username']          = $p['Username'];
            
                $totals['HealthInsurance']   += $p['HealthInsurance'];
                $totals['LoanInsurance']     += $p['LoanInsurance'];
                $totals['AdministrativeFee'] += $p['AdministrativeFee'];
                $totals['Principal']         += $p['Principal'];
                $totals['Interest']          += $p['Interest'];
                $totals['Pmt']               += $p['Pmt'];
                $totals['Penalties']         += $p['Penalties'];
                $totals['Delay']             += $p['Delay'];
                $c++;
            } 
        }
        $balanceKp = $this->_plan->balanceKp;
        
        while($balanceKp > 0) {
            
 	    $data[$c] = $this->_nextPaymentData();
    
            $this->_plan->balanceKp = $data[$c]['balanceKp'];
            $this->_plan->balanceKh = $data[$c]['balanceKh'];
            $this->_plan->balanceKl = $data[$c]['balanceKl'];
            $this->_plan->balanceKa = $data[$c]['balanceKa'];
            
            $this->_plan->xpPmtDate = $data[$c]['xpPmtDate']; //
            $this->_plan->xpPmt	    = $data[$c]['xpPmt'];
            $this->_plan->rFromDate = $data[$c]['rFromDate']; //
    
            $pmt[$c]['inx']               = $c + 1;
            $pmt[$c]['Date']              = $data[$c]['rFromDate'];
            $pmt[$c]['HealthInsurance']   = $data[$c]['hFee'];
            $pmt[$c]['LoanInsurance']     = $data[$c]['lFee'];
            $pmt[$c]['AdministrativeFee'] = $data[$c]['aFee'];
            $pmt[$c]['Principal']         = $data[$c]['principal'];
            $pmt[$c]['Interest']          = $data[$c]['interest']; //
            $pmt[$c]['Pmt']               = $data[$c]['pmt'];
            $pmt[$c]['Penalties']         = $data[$c]['penalties'];
            $pmt[$c]['Delay']             = $data[$c]['delay'];
            $pmt[$c]['BalancePrincipal']  = $data[$c]['balanceKp'];
            $pmt[$c]['ReceiptId']         = '-';
            $pmt[$c]['TransactionId']     = '-';
            $pmt[$c]['Username']          = '-';
    
            $totals['HealthInsurance']   += $data[$c]['hFee'];
            $totals['LoanInsurance']     += $data[$c]['lFee'];
            $totals['AdministrativeFee'] += $data[$c]['aFee'];
            $totals['Principal']         += $data[$c]['principal'];
            $totals['Interest']          += $data[$c]['interest'];
            $totals['Pmt']               += $data[$c]['pmt'];
            $totals['Penalties']         += $data[$c]['penalties'];
            $totals['Delay']             += $data[$c]['delay'];
       
            $balanceKp                    =  $data[$c]['balanceKp'];
            $c++;      
        }
        
        if ($c > 0) {
            $pmt[0]['Pmt']      += $this->_gracePmt;
            $pmt[0]['Interest'] += $this->_gracePmt;
            $totals['Pmt']      += $this->_gracePmt;
            $totals['Interest'] += $this->_gracePmt;
        }
        
        return array('meta' => $this->_metadata, 'data' => $pmt, 'total' => $totals);
    } 

    protected function _nextPaymentData()
    {       
        $data = array();        
        $balance = $this->_plan->balanceKp + $this->_plan->balanceKh + $this->_plan->balanceKl + $this->_plan->balanceKa;    
        $rFromDate = new Zend_Date($this->_plan->rFromDate);
        $pmtDate = new Zend_Date($this->_plan->xpPmtDate);  
        $n = ceil($pmtDate->sub($rFromDate)->toValue()/60/60/24);

        $data['xpPmtDate'] = $this->_nextPaymentDate();
        $data['rFromDate'] = $this->_plan->xpPmtDate;
        
        $data['interest']  = round(($balance*0.01*($this->_annualPercentageRate/$this->_calendarType)*$n),2);
        $data['hFee']      = round(($this->_plan->khP * ($this->_plan->pmt - $data['interest'])),2);
        $data['lFee']      = round(($this->_plan->klP * ($this->_plan->pmt - $data['interest'])),2);
        $data['aFee']      = round(($this->_plan->kaP * ($this->_plan->pmt - $data['interest'])),2);
        $data['principal'] = $this->_plan->pmt - $data['interest'] - $data['hFee'] - $data['lFee'] - $data['aFee'];
        
        $data['balanceKp'] = round($this->_plan->balanceKp - $data['principal'],2);
        $data['balanceKh'] = round($this->_plan->balanceKh - $data['hFee'],2);
        $data['balanceKl'] = round($this->_plan->balanceKl - $data['lFee'],2);
        $data['balanceKa'] = round($this->_plan->balanceKa - $data['aFee'],2);
        
        $data['penalties'] = 0;
        $data['delay'] = 0;
        
        if($this->_loan) {
            $currentDate = new Zend_Date(date('Y-m-d'));
            $pmtDate = new Zend_Date($this->_plan->xpPmtDate);  
            if($currentDate >= $pmtDate) {
                $data['delay'] = ceil($currentDate->sub($pmtDate)->toValue()/60/60/24);
                if ($data['delay'] > $this->_loan->d->DelayGrace) {
                    $data['penalties'] = round($data['delay'] * $this->_plan->pmt * ($this->_loan->d->DelayPenaltyRate/100) + $this->_loan->d->DelayPenaltyFixedCharge,2);
                }
            } else {
                $data['delay'] = 0;
            }
        }
        
        $data['pmt']       = $this->_plan->pmt + $data['penalties'];
        $data['xpPmt']     = min($data['pmt'], $balance + $data['interest'] + $data['penalties']);
        
        if ($balance < $this->_plan->pmt) {
          $data['hFee']      = $this->_plan->balanceKh;
          $data['lFee']      = $this->_plan->balanceKl;
          $data['aFee']      = $this->_plan->balanceKa;
          $data['principal'] = $this->_plan->balanceKp;
          $data['balanceKp'] = 0;
          $data['balanceKh'] = 0;
          $data['balanceKl'] = 0;
          $data['balanceKa'] = 0;
          $data['pmt']       = $data['interest'] + $data['hFee'] + $data['lFee'] + $data['aFee'] + $data['principal'] + $data['penalties'];
          $data['xpPmt']     = 0;
        }
        return $data;
    }
    
    protected function _nextPaymentDate($pdate = '')
    { 
        $date = new Zend_Date($pdate ? $pdate : $this->_plan->xpPmtDate);
        switch($this->_paymentFrequency) {
            case "W" : $date->addDay(7);   break;
            case "BW": $date->addDay(14);  break;
            case "M" : $date->addMonth(1); break;
            case "Q" : $date->addMonth(3); break;
            case "SA": $date->addMonth(6); break;
            case "A" : $date->addYear(1);  break;
        }
        return $date->get('Y-m-d');
    }
    
    protected function _setTerm()
    {
        $date = $this->_firstPaymentDate;
        for($i=1;$i<$this->_installments;$i++) {
           $date = $this->_nextPaymentDate($date); 
        }
        $d1 = new Zend_Date($this->_principalGraceEndDate);
        $d2 = new Zend_Date($date); 
        $this->_term = ceil($d2->sub($d1)->toValue()/60/60/24);        
        return $this;
    }

    protected function _setPmt()
    {
        if ($this->_loan) {
            $this->_pmt = $this->_loan->d->PaymentMnt;
            return $this;
        }
        $i = (($this->_annualPercentageRate/100)*$this->_term)/($this->_calendarType*$this->_installments);
        $kpTotal = $this->_principal * ((100 + $this->_loanInsurancePct + $this->_healthInsurancePct + $this->_administrativeFeePct)/100);
        $this->_pmt = round(($kpTotal * $i)/(1-pow((1/(1+$i)),$this->_installments)),2);
        return $this;
    }
    
    protected function _setGracePmt()
    {
        $balance = $this->_principal +
                0.01 * $this->_principal * $this->_healthInsurancePct +
                0.01 * $this->_principal * $this->_loanInsurancePct +
                0.01 * $this->_principal * $this->_administrativeFeePct;
        $this->_gracePmt = round((($balance)*0.01*($this->_principalGraceRate/$this->_calendarType)*$this->_principalGrace),2);    
        return $this;
    }
        
    protected function _setAnnualPercentageRate($annualPercentageRate)
    {
        if((!is_numeric($annualPercentageRate))||($annualPercentageRate < 0)) 
            throw new Exception($this->translate("Invalid annual percentage rate"));
        $this->_annualPercentageRate = $annualPercentageRate;
        return $this;
    }
         
    protected function _setCalendarType($calendarType)
    {
        if(($calendarType != 360)&&($calendarType != 365)) 
            throw new Exception($this->translate("Invalid calendar type"));
        $this->_calendarType = $calendarType;
        return $this;
    }
         
    protected function _setInstallments($installments)
    {
        if((!is_numeric($installments))||($installments <= 0)) 
            throw new Exception($this->translate("Invalid number of installments"));
        $this->_installments = $installments;
        return $this;
    }
         
    protected function _setInterestCalculation($interestCalculation)
    {        
        switch($interestCalculation) {
            case "Declining"; case "Flat"; break;
            default: throw new Exception($this->translate("Invalid interest calculation method"));
        }
        $this->_interestCalculation = $interestCalculation;
        return $this;
    }
         
    protected function _setPaymentFrequency($paymentFrequency)
    {        
        switch($paymentFrequency) {
            case "W"; case "BW"; case "M"; case "Q"; case "SA"; case "A"; break;
            default: throw new Exception($this->translate("Invalid payment frequency"));
        }
        $this->_paymentFrequency = $paymentFrequency;
        return $this;
    }
         
    protected function _setLoanInsurancePct($loanInsurancePct)
    {
        if((!is_numeric($loanInsurancePct))||($loanInsurancePct < 0)) 
            throw new Exception($this->translate("Invalid loan insurance fee"));
        $this->_loanInsurancePct = $loanInsurancePct;
        return $this;
    }
         
    protected function _setHealthInsurancePct($healthInsurancePct)
    {
        if((!is_numeric($healthInsurancePct))||($healthInsurancePct < 0)) 
            throw new Exception($this->translate("Invalid health insurance fee"));
        $this->_healthInsurancePct = $healthInsurancePct;
        return $this;
    }
    
    protected function _setAdministrativeFeePct($administrativeFeePct)
    {
        if((!is_numeric($administrativeFeePct))||($administrativeFeePct < 0)) 
            throw new Exception($this->translate("Invalid administrative fee"));
        $this->_administrativeFeePct = $administrativeFeePct;
        return $this;
    }
    
    protected function _setPrincipalGraceRate($principalGraceRate)
    {
        if((!is_numeric($principalGraceRate))||($principalGraceRate < 0)) 
            throw new Exception($this->translate("Invalid principal grace rate"));
        $this->_principalGraceRate = $principalGraceRate;
        return $this;
    }
    
    protected function _setPrincipal($principal)
    {
        if((!is_numeric($principal))||($principal <= 0)) 
            throw new Exception($this->translate("Invalid principal"));
        $this->_principal = $principal;
        return $this;
    }
    
    protected function _setDeliveryDate($deliveryDate)
    {
        if(!$this->_isWeekday($deliveryDate)) 
            throw new Exception($this->translate("Invalid delivery date or weekend")); 
        $this->_deliveryDate = $deliveryDate;
        return $this;
    }
    
    protected function _setFirstPaymentDate($firstPaymentDate)
    {
        if(!$this->_loan->d->DeliveryDate) {
            if(!$this->_isWeekday($firstPaymentDate)) 
                throw new Exception($this->translate("Invalid first payment date or weekend")); 
        }
        if($firstPaymentDate <= $this->_deliveryDate)
            throw new Exception($this->translate("Invalid first payment date"));       
        $this->_firstPaymentDate = $firstPaymentDate;
        return $this;
    }
            
    protected function _setPrincipalGraceEndDate()
    {
        $date = new Zend_Date($this->_firstPaymentDate);
        switch($this->_paymentFrequency) {
            case "W" : $date->subDay(7);   break;
            case "BW": $date->subDay(14);  break;
            case "M" : $date->subMonth(1); break;
            case "Q" : $date->subMonth(3); break;
            case "SA": $date->subMonth(6); break;
            case "A" : $date->subYear(1);  break;
        }
        $this->_principalGraceEndDate = ($date->compareDate($this->_deliveryDate, 'Y-m-d') > 0) ?
                $date->get('Y-m-d') : $this->_deliveryDate;
        return $this;
    }
    
    protected function _setPrincipalGraceMargin($principalGrace)
    {        
        if((!is_numeric($principalGrace))||($principalGrace < 0)) 
            throw new Exception($this->translate("Invalid principal grace"));        
        $this->_principalGraceMargin = $principalGrace;
        return $this;
    }
    
    protected function _setPrincipalGrace()
    {        
        $date = new Zend_Date($this->_principalGraceEndDate);        
        $n = ceil($date->sub(new Zend_Date($this->_deliveryDate))->toValue()/60/60/24); 
        if(!$this->_loan->d->DeliveryDate) {
            if($n > $this->_principalGraceMargin) 
                throw new Exception($this->translate("Principal grace margin exceeded"));
        }
        $this->_principalGrace = $n;
        return $this;
    }
    
    protected function _setDelayGrace($delayGrace)
    {        
        if((!is_numeric($delayGrace))||($delayGrace < 0)) 
            throw new Exception($this->translate("Invalid delay grace"));        
        $this->_delayGrace = $delayGrace;
        return $this;
    }
        
    protected function _setDelayPenaltyRate($delayPenaltyRate)
    {
        if((!is_numeric($delayPenaltyRate))||($delayPenaltyRate < 0)) 
            throw new Exception($this->translate("Invalid delay penalty rate"));
        $this->_delayPenaltyRate = $delayPenaltyRate;
        return $this;
    }
    
    protected function _setDelayPenaltyFixedCharge($delayPenaltyFixedCharge)
    {
        if((!is_numeric($delayPenaltyFixedCharge))||($delayPenaltyFixedCharge < 0)) 
            throw new Exception($this->translate("Invalid delay penalty fixed charge"));
        $this->_delayPenaltyFixedCharge = $delayPenaltyFixedCharge;
        return $this;
    }
    
    protected function _isWeekday($date)
    {
        if(!Zend_Date::isDate($date, 'YYYY-MM-DD')) return false;
        $d = new Zend_Date($date);
        if(($d->get('w') == 0)||($d->get('w') == 6)) return false;
        return true;
    }
        
    protected function _setMetadata()
    {
        $this->_metadata = array();
        $this->_metadata['title'] = $this->translate("Payment Plan");
        $this->_metadata['headers'] = array
            (
                array('inx',               30, $this->translate("#"),              'Number'),
                array('Date',              80, $this->translate("Date"),           'DateTime', 'Date'),
                array('HealthInsurance',   80, $this->translate("Health ins."),    'Number',   'Standard'),
                array('LoanInsurance',     80, $this->translate("Loan ins."),      'Number',   'Standard'),
                array('AdministrativeFee', 80, $this->translate("Admin. fee"),     'Number',   'Standard'),
                array('Principal',         80, $this->translate("Principal"),      'Number',   'Standard'),
                array('Interest',          80, $this->translate("Interest"),       'Number',   'Standard'),
                array('Pmt',               80, $this->translate("Payment"),        'Number',   'Standard'),
                array('Penalties',         80, $this->translate("Penalties"),      'Number',   'Standard'),
                array('Delay',             60, $this->translate("Delay"),          'Number'),
                array('BalancePrincipal',  80, $this->translate("Principal bal."), 'Number',   'Standard'),
                array('ReceiptId',         80, $this->translate("Receipt"),        'Number'),
                array('TransactionId',     80, $this->translate("Transaction"),    'String'),
                array('Username',          80, $this->translate("Username"),       'String')
            );
        return $this;
    }	

    public function translate($value)
    {            
        return Zend_Registry::get('Zend_Translate')->_($value);
    }
    
    public function getPrincipalGraceEndDate()
    {
        return $this->_principalGraceEndDate;
    }
    
    public function getPrincipalGraceInterestCharged()
    {
        return $this->_gracePmt;
    }
    
    public function getSchedule()
    {
        return $this->_plan->schedule;
    }
    
    public function toArray() 
    {
        return array(
            'InterestCalculation' => $this->_interestCalculation,
            'CalendarType' => $this->_calendarType,
            'Installments' => $this->_installments,
            'PaymentFrequency' => $this->_paymentFrequency,
            'DeliveryDate' => $this->_deliveryDate,
            'FirstPaymentDate' => $this->_firstPaymentDate,
            'AnnualPercentageRate' => $this->_annualPercentageRate,
            'LoanInsurancePct' => $this->_loanInsurancePct,
            'HealthInsurancePct' => $this->_healthInsurancePct,
            'AdministrativeFeePct' => $this->_administrativeFeePct,
            'PrincipalGraceRate' => $this->_principalGraceRate,
            'Principal' => $this->_principal,
            'PrincipalGraceEndDate' => $this->_principalGraceEndDate,
            'PrincipalGraceMargin' => $this->_principalGraceMargin,
            'PrincipalGrace' => $this->_principalGrace,
            'DelayGrace' => $this->_delayGrace,
            'DelayPenaltyRate' => $this->_delayPenaltyRate,
            'DelayPenaltyFixedCharge' => $this->_delayPenaltyFixedCharge,
            'Term' => $this->_term,
            'Pmt' => $this->_pmt,
            'GracePmt' => $this->_gracePmt,
            'Schedule' => $this->_plan->schedule
        );
    }
    
    static function getMaxFirstPaymentDate($deliveryDate, $principalGrace, $paymentFrequency)
    {
        $pmtPlan = new Emms_Class_Loan_PmtPlan();
        try {
            $pmtPlan->_setDeliveryDate($deliveryDate);
            $pmtPlan->_setPrincipalGraceMargin($principalGrace);
            $pmtPlan->_setPaymentFrequency($paymentFrequency);
            $d = new Zend_Date($deliveryDate);
            return $pmtPlan->_nextPaymentDate($d->addDay($principalGrace)->get('Y-m-d'));
        } catch (Exception $e) {
            throw new Exception($e->getMessage());
        }
    }
}

class plan 
{
        public $pmt;
        
        public $kp;
        public $kh;
        public $kl;
        public $ka;
        
        public $kpP;
        public $khP;
        public $klP;
        public $kaP;
        
        public $balanceKp;
        public $balanceKh;
        public $balanceKl;
        public $balanceKa;
        
        //public $annualEffectiveRate;
                
        public $xpPmtDate;
        public $xpPmt;
        public $rFromDate;
        
        public $schedule;
}